﻿using System.Reflection;
using System;
using System.Collections.Generic;

namespace MyTestRunner.Infrastructure
{
    /// <summary>
    /// Container with methods that make reflection a little easier.
    /// </summary>
    public static class ReflectionHelper
    {
        /// <summary>
        /// Returns the methodinfo for the given delegate.
        /// </summary>
        public static MethodInfo GetMethod(Action methodDelegate)
        {
            if (methodDelegate == null) throw new ArgumentNullException("methodDelegate");
            return methodDelegate.Method;
        }

        /// <summary>
        /// Returns the public instance methods that have the given attribute.
        /// </summary>
        public static IEnumerable<MethodInfo> FindPublicMethodsWithAttribute(Assembly assembly, string attributeName)
        {
            if (assembly == null) throw new ArgumentNullException("assembly");
            if (string.IsNullOrEmpty(attributeName)) throw new ArgumentException("attributeName");

            foreach (Type type in assembly.GetExportedTypes())
            {
                foreach (MethodInfo method in FindPublicMethodsWithAttribute(type, attributeName))
                {
                    yield return method;
                }
            }
        }

        /// <summary>
        /// Returns the public instance methods that have the given attribute.
        /// </summary>
        public static IEnumerable<MethodInfo> FindPublicMethodsWithAttribute(Type type, string attributeName)
        {
            if (type == null) throw new ArgumentNullException("type");
            if (string.IsNullOrEmpty(attributeName)) throw new ArgumentException("attributeName");

            foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public))
            {
                foreach (Attribute attribute in method.GetCustomAttributes(true))
                {
                    if (attribute.GetType().FullName == attributeName)
                    {
                        yield return method;
                        break;
                    }
                }
            }
        }
    }
}
